Make GTK+ work as an untrusted X client. (#136571, Ed Catmur)
authorMatthias Clasen <mclasen@redhat.com>
Thu, 25 May 2006 05:30:14 +0000 (05:30 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Thu, 25 May 2006 05:30:14 +0000 (05:30 +0000)
2006-05-25  Matthias Clasen  <mclasen@redhat.com>

Make GTK+ work as an untrusted X client. (#136571,
Ed Catmur)

ChangeLog
ChangeLog.pre-2-10
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkdisplay-x11.h
gdk/x11/gdkdnd-x11.c
gdk/x11/gdkevents-x11.c
gdk/x11/gdkmain-x11.c
gdk/x11/gdkwindow-x11.c
gtk/gtkcolorsel.c
gtk/gtkinvisible.c
gtk/gtkwidget.c

index e53f1cfb101c3359af095d0cbe5ed2ced9bc50a4..cc8143eee321ae709c75277a1a4dbf675cf0cec8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,59 @@
+2006-05-25  Matthias Clasen  <mclasen@redhat.com>
+
+       Make GTK+ work as an untrusted X client. (#136571,
+       Ed Catmur)
+
+       * gdk/x11/gdkdisplay-x11.h:
+       * gdk/x11/gdkdisplay-x11.c (gdk_display_open): When 
+       opening a display, determine if we are untrusted.
+       
+       * gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete): 
+       Just bail out when we are untrusted.
+
+       * gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around
+       a bug in the Xorg XSECURITY implementation by coercing
+       toplevel InputOnly windows to InputOutput.
+
+       * gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer): 
+       (_gdk_windowing_window_get_pointer): 
+       When untrusted, call XQueryPointer on an auxiliary
+       window, not on the root window.
+       
+       * gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer): 
+       If untrusted, loop through all GDK-aware toplevels on all
+       screens in the hope we hit one containing the pointer; 
+       then use that as the basis of the current XQueryPointer 
+       child recursion.
+
+       * gdk/x11/gdkmain-x11.c (gdk_pointer_grab): 
+       (gdk_keyboard_grab): Ignore failed grabs when untrusted.
+
+       * gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only
+       cache our own toplevels when untrusted.
+
+       * gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try
+       to do Motif DND as untrusted client.
+
+       * gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window): 
+       (gdk_x11_screen_get_window_manager_name): 
+       (gdk_x11_screen_supports_net_wm_hint): 
+       Bail out early if untrusted.
+       
+       * gtk/gtkcolorsel.c (grab_color_at_mouse): If getting 
+       the color under the pointer by screenshooting the root 
+       window fails, it tries to get the color from our own 
+       window.
+
+       * gtk/gtkcolorsel.c (get_screen_color): Make the
+       dropper_grab_widget a child of the dialog, not a 
+       toplevel.
+
+       * gtk/gtkinvisible.c (gtk_invisible_realize): Respect
+       a parent window that has been set before realizing.
+
+       * gtk/gtkwidget.c (gtk_widget_get_parent_window): 
+       Always return a previously set parent window.
+       
 2006-05-24  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkfontbutton.c (gtk_font_button_clicked): 
index e53f1cfb101c3359af095d0cbe5ed2ced9bc50a4..cc8143eee321ae709c75277a1a4dbf675cf0cec8 100644 (file)
@@ -1,3 +1,59 @@
+2006-05-25  Matthias Clasen  <mclasen@redhat.com>
+
+       Make GTK+ work as an untrusted X client. (#136571,
+       Ed Catmur)
+
+       * gdk/x11/gdkdisplay-x11.h:
+       * gdk/x11/gdkdisplay-x11.c (gdk_display_open): When 
+       opening a display, determine if we are untrusted.
+       
+       * gdk/x11/gdkdisplay-x11.c (gdk_notify_startup_complete): 
+       Just bail out when we are untrusted.
+
+       * gdk/x11/gdkwindow-x11.c (gdk_window_new): Work around
+       a bug in the Xorg XSECURITY implementation by coercing
+       toplevel InputOnly windows to InputOutput.
+
+       * gdk/x11/gdkwindow-x11.c (_gdk_windowing_get_pointer): 
+       (_gdk_windowing_window_get_pointer): 
+       When untrusted, call XQueryPointer on an auxiliary
+       window, not on the root window.
+       
+       * gdk/x11/gdkwindow-x11.c (_gdk_windowing_window_at_pointer): 
+       If untrusted, loop through all GDK-aware toplevels on all
+       screens in the hope we hit one containing the pointer; 
+       then use that as the basis of the current XQueryPointer 
+       child recursion.
+
+       * gdk/x11/gdkmain-x11.c (gdk_pointer_grab): 
+       (gdk_keyboard_grab): Ignore failed grabs when untrusted.
+
+       * gdk/x11/gdkdnd-x11.c (gdk_window_cache_new): Only
+       cache our own toplevels when untrusted.
+
+       * gdk/x11/gdkdnd-x11.c (motif_send_enter): Don't try
+       to do Motif DND as untrusted client.
+
+       * gdk/x11/gdkevents-x11.c (fetch_net_wm_check_window): 
+       (gdk_x11_screen_get_window_manager_name): 
+       (gdk_x11_screen_supports_net_wm_hint): 
+       Bail out early if untrusted.
+       
+       * gtk/gtkcolorsel.c (grab_color_at_mouse): If getting 
+       the color under the pointer by screenshooting the root 
+       window fails, it tries to get the color from our own 
+       window.
+
+       * gtk/gtkcolorsel.c (get_screen_color): Make the
+       dropper_grab_widget a child of the dialog, not a 
+       toplevel.
+
+       * gtk/gtkinvisible.c (gtk_invisible_realize): Respect
+       a parent window that has been set before realizing.
+
+       * gtk/gtkwidget.c (gtk_widget_get_parent_window): 
+       Always return a previously set parent window.
+       
 2006-05-24  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkfontbutton.c (gtk_font_button_clicked): 
index 1304a831250261a61dac43e6c31dd1b72cc87486..af90587f76bfa3f27e7d01dc1994fc252fdd1400 100644 (file)
@@ -219,6 +219,24 @@ gdk_display_open (const gchar *display_name)
     }
 #endif
 
+  display_x11->trusted_client = TRUE;
+  {
+    Window root, child;
+    int rootx, rooty, winx, winy;
+    unsigned int xmask;
+
+    gdk_error_trap_push ();
+    XQueryPointer (display_x11->xdisplay, 
+                  GDK_SCREEN_X11 (display_x11->default_screen)->xroot_window,
+                  &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+    gdk_flush ();
+    if (G_UNLIKELY (gdk_error_trap_pop () == BadWindow)) 
+      {
+       g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
+       display_x11->trusted_client = FALSE;
+      }
+  }
+
   if (_gdk_synchronize)
     XSynchronize (display_x11->xdisplay, True);
   
@@ -1056,6 +1074,9 @@ gdk_notify_startup_complete (void)
   if (display_x11->startup_notification_id == NULL)
     return;
 
+  if (!G_LIKELY (display_x11->trusted_client))
+    return;
+
   escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
   message = g_strdup_printf ("remove: ID=%s", escaped_id);
   g_free (escaped_id);
index 36defc8d98fe25e78729160e0915573f359bc412..14b8fd5b293262593b09137cd5f55fee3800ff9d 100644 (file)
@@ -81,6 +81,11 @@ struct _GdkDisplayX11
   gboolean have_xfixes;
   gint xfixes_event_base;
 
+  /* If the SECURITY extension is in place, whether this client holds 
+   * a trusted authorization and so is allowed to make various requests 
+   * (grabs, properties etc.) Otherwise always TRUE. */
+  gboolean trusted_client;
+
   /* Information about current pointer and keyboard grabs held by this
    * client. If gdk_pointer_xgrab_window or gdk_keyboard_xgrab_window
    * window is NULL, then the other associated fields are ignored
index b4eb8e9d39e1e65c13d5663e8ff6d6b2a1fb4cef..7e0961c7711fe23ddc525004e4906dc688d20d0e 100644 (file)
@@ -460,6 +460,25 @@ gdk_window_cache_new (GdkScreen *screen)
 
   XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
   result->old_event_mask = xwa.your_event_mask;
+
+  if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) 
+    {
+      GList *toplevel_windows, *list;
+      GdkWindow *window;
+      gint x, y, width, height;
+      
+      toplevel_windows = gdk_screen_get_toplevel_windows (screen);
+      for (list = toplevel_windows; list; list = list->next) {
+       window = GDK_WINDOW (list->data);
+       gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
+       gdk_window_cache_add (result, GDK_WINDOW_XID (window), 
+                             x, y, width, height, 
+                             gdk_window_is_visible (window));
+      }
+      g_list_free (toplevel_windows);
+      return result;
+    }
+
   XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
                result->old_event_mask | SubstructureNotifyMask);
   gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
@@ -1287,6 +1306,9 @@ motif_send_enter (GdkDragContext  *context,
   GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
   XEvent xev;
 
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return; /* Motif Dnd requires getting properties on the root window */
+
   xev.xclient.type = ClientMessage;
   xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
   xev.xclient.format = 8;
index 46cdd12857f174d8478dab5a4af98b250bd354e4..d64925b9e5bb567f98a7e7c3e021d08c700d0f84 100644 (file)
@@ -2574,6 +2574,8 @@ fetch_net_wm_check_window (GdkScreen *screen)
   
   screen_x11 = GDK_SCREEN_X11 (screen);
   display = screen_x11->display;
+
+  g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
   
   if (screen_x11->wmspec_check_window != None)
     return; /* already have it */
@@ -2631,6 +2633,9 @@ gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
 
   screen_x11 = GDK_SCREEN_X11 (screen);
   
+  if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
+    return screen_x11->window_manager_name;
+
   fetch_net_wm_check_window (screen);
 
   if (screen_x11->need_refetch_wm_name)
@@ -2726,6 +2731,9 @@ gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
   screen_x11 = GDK_SCREEN_X11 (screen);
   display = screen_x11->display;
 
+  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+    return FALSE;
+
   supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
   if (!supported_atoms)
     {
index 72f7339749d399d6ae0d9e818e54cd5ee820e266..75e69479d3961c3a3e857d90ed0187ec0d47af6c 100644 (file)
@@ -191,6 +191,7 @@ gdk_pointer_grab (GdkWindow *         window,
 {
   gint return_val;
   GdkCursorPrivate *cursor_private;
+  GdkDisplayX11 *display_x11;
   guint xevent_mask;
   Window xwindow;
   Window xconfine_to;
@@ -202,6 +203,8 @@ gdk_pointer_grab (GdkWindow *         window,
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
   g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
   
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+
   cursor_private = (GdkCursorPrivate*) cursor;
   
   xwindow = GDK_WINDOW_XID (window);
@@ -233,7 +236,8 @@ gdk_pointer_grab (GdkWindow *         window,
                                        confine_to,
                                        time);
 
-  if (return_val == GrabSuccess)
+  if (return_val == GrabSuccess || 
+      G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
     {
       if (!GDK_WINDOW_DESTROYED (window))
        {
@@ -257,7 +261,6 @@ gdk_pointer_grab (GdkWindow *         window,
   
   if (return_val == GrabSuccess)
     {
-      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
       if (display_x11->pointer_xgrab_window != NULL &&
          display_x11->pointer_xgrab_window != (GdkWindowObject *)window)
        generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_xgrab_window),
@@ -338,10 +341,13 @@ gdk_keyboard_grab (GdkWindow *       window,
 {
   gint return_val;
   unsigned long serial;
+  GdkDisplayX11 *display_x11;
   
   g_return_val_if_fail (window != NULL, 0);
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
   
+  display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
+
   serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
 
   if (!GDK_WINDOW_DESTROYED (window))
@@ -356,13 +362,16 @@ gdk_keyboard_grab (GdkWindow *       window,
                                    owner_events,
                                    GrabModeAsync, GrabModeAsync,
                                    time);
+       if (G_UNLIKELY (!display_x11->trusted_client && 
+                       return_val == AlreadyGrabbed))
+         /* we can't grab the keyboard, but we can do a GTK-local grab */
+         return_val = GrabSuccess;
     }
   else
     return_val = AlreadyGrabbed;
 
   if (return_val == GrabSuccess)
     {
-      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
       if (display_x11->keyboard_xgrab_window != NULL &&
          display_x11->keyboard_xgrab_window != (GdkWindowObject *)window)
        generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
index dd26bca9967c41d471f7486219b5944c9210d4d3..55b153a9ba32f833ff84f3a160198a1023b48a34 100644 (file)
@@ -88,6 +88,7 @@ static void     gdk_window_add_colormap_windows   (GdkWindow  *window);
 static void     set_wm_name                       (GdkDisplay  *display,
                                                   Window       xwindow,
                                                   const gchar *name);
+static void     move_to_current_desktop           (GdkWindow *window);
 
 static GdkColormap* gdk_window_impl_x11_get_colormap (GdkDrawable *drawable);
 static void         gdk_window_impl_x11_set_colormap (GdkDrawable *drawable,
@@ -731,6 +732,17 @@ gdk_window_new (GdkWindow     *parent,
   else
     private->window_type = attributes->window_type;
 
+  /* Work around a bug where Xorg refuses to map toplevel InputOnly windows 
+   * from an untrusted client: http://bugs.freedesktop.org/show_bug.cgi?id=6988
+   */
+  if (attributes->wclass == GDK_INPUT_ONLY &&
+      GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT &&
+      !G_LIKELY (GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (parent))->trusted_client))
+    {
+      g_warning ("Coercing GDK_INPUT_ONLY toplevel window to GDK_INPUT_OUTPUT to work around bug in Xorg server");
+      attributes->wclass = GDK_INPUT_OUTPUT;
+    }
+
   _gdk_window_init_position (GDK_WINDOW (private));
   if (impl->position_info.big)
     private->guffaw_gravity = TRUE;
@@ -2007,7 +2019,13 @@ gdk_x11_window_move_to_current_desktop (GdkWindow *window)
 
   if (toplevel->on_all_desktops)
     return;
+  
+  move_to_current_desktop (window);
+}
 
+static void
+move_to_current_desktop (GdkWindow *window)
+{
   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
                                           gdk_atom_intern_static_string ("_NET_WM_DESKTOP")))
     {
@@ -3428,6 +3446,8 @@ _gdk_windowing_get_pointer (GdkDisplay       *display,
                            GdkModifierType  *mask)
 {
   GdkScreen *default_screen;
+  Display *xdisplay;
+  Window xwindow;
   Window root = None;
   Window child;
   int rootx, rooty;
@@ -3439,10 +3459,27 @@ _gdk_windowing_get_pointer (GdkDisplay       *display,
     return;
 
   default_screen = gdk_display_get_default_screen (display);
+
+  xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
+  xwindow = GDK_SCREEN_XROOTWIN (default_screen);
   
-  XQueryPointer (GDK_SCREEN_XDISPLAY (default_screen),
-                GDK_SCREEN_XROOTWIN (default_screen),
-                &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) 
+    {
+      XQueryPointer (xdisplay, xwindow,
+                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+    } 
+  else 
+    {
+      XSetWindowAttributes attributes;
+      Window w;
+      
+      w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0, 
+                        CopyFromParent, InputOnly, CopyFromParent, 
+                        0, &attributes);
+      XQueryPointer (xdisplay, w, 
+                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+      XDestroyWindow (xdisplay, w);
+    }
   
   if (root != None)
     {
@@ -3476,13 +3513,28 @@ _gdk_windowing_window_get_pointer (GdkDisplay      *display,
   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
 
   return_val = NULL;
-  if (!GDK_WINDOW_DESTROYED (window) &&
-      XQueryPointer (GDK_WINDOW_XDISPLAY (window),
-                    GDK_WINDOW_XID (window),
-                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
+  if (!GDK_WINDOW_DESTROYED (window)) 
     {
-      if (child)
-       return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child);
+      if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) 
+       {
+         if (XQueryPointer (GDK_WINDOW_XDISPLAY (window),
+                            GDK_WINDOW_XID (window),
+                            &root, &child, &rootx, &rooty, &winx, &winy, &xmask))
+           {
+             if (child)
+               return_val = gdk_window_lookup_for_display (GDK_WINDOW_DISPLAY (window), child);
+           }
+       } 
+      else 
+       {
+         GdkScreen *screen;
+         int originx, originy;
+         _gdk_windowing_get_pointer (gdk_drawable_get_display (window), &screen, 
+                                     &rootx, &rooty, &xmask);
+         gdk_window_get_origin (window, &originx, &originy);
+         winx = rootx - originx;
+         winy = rooty - originy;
+       }
     }
   
   *x = winx + xoffset;
@@ -3555,24 +3607,89 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
    * and the result.
    */
   gdk_x11_display_grab (display);
-  XQueryPointer (xdisplay, xwindow,
-                &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
-
-  if (root == xwindow)
-    xwindow = child;
-  else
-    xwindow = root;
-  
-  while (xwindow)
+  if (G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client)) 
     {
-      xwindow_last = xwindow;
       XQueryPointer (xdisplay, xwindow,
-                    &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
+                    &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+      if (root == xwindow)
+       xwindow = child;
+      else
+       xwindow = root;
+      
+      while (xwindow)
+       {
+         xwindow_last = xwindow;
+         XQueryPointer (xdisplay, xwindow,
+                        &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
+       }
+    } 
+  else 
+    {
+      gint i, screens, width, height;
+      GList *toplevels, *list;
+      Window pointer_window;
+      
+      pointer_window = None;
+      screens = gdk_display_get_n_screens (display);
+      for (i = 0; i < screens; ++i) {
+       screen = gdk_display_get_screen (display, i);
+       toplevels = gdk_screen_get_toplevel_windows (screen);
+       for (list = toplevels; list != NULL; list = g_list_next (list)) {
+         window = GDK_WINDOW (list->data);
+         xwindow = GDK_WINDOW_XWINDOW (window);
+         gdk_error_trap_push ();
+         XQueryPointer (xdisplay, xwindow,
+                        &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+         gdk_flush ();
+         if (gdk_error_trap_pop ())
+           continue;
+         if (child != None) 
+           {
+             pointer_window = child;
+             break;
+           }
+         gdk_window_get_geometry (window, NULL, NULL, &width, &height, NULL);
+         if (winx >= 0 && winy >= 0 && winx < width && winy < height) 
+           {
+             /* A childless toplevel, or below another window? */
+             XSetWindowAttributes attributes;
+             Window w;
+             
+             w = XCreateWindow (xdisplay, xwindow, winx, winy, 1, 1, 0, 
+                                CopyFromParent, InputOnly, CopyFromParent, 
+                                0, &attributes);
+             XMapWindow (xdisplay, w);
+             XQueryPointer (xdisplay, xwindow, 
+                            &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
+             XDestroyWindow (xdisplay, w);
+             if (child == w) 
+               {
+                 pointer_window = xwindow;
+                 break;
+               }
+           }
+       }
+       g_list_free (toplevels);
+       if (pointer_window != None)
+         break;
+      }
+      xwindow = pointer_window;
+
+      while (xwindow)
+       {
+         xwindow_last = xwindow;
+         gdk_error_trap_push ();
+         XQueryPointer (xdisplay, xwindow,
+                        &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
+         gdk_flush ();
+         if (gdk_error_trap_pop ())
+           break;
+       }
     }
+  
   gdk_x11_display_ungrab (display);
 
-  window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen),
-                                         xwindow_last);
+  window = gdk_window_lookup_for_display (display, xwindow_last);
   *win_x = window ? winx : -1;
   *win_y = window ? winy : -1;
 
@@ -4480,52 +4597,12 @@ gdk_window_unstick (GdkWindow *window)
 
   if (GDK_WINDOW_IS_MAPPED (window))
     {
-      XEvent xev;
-      Atom type;
-      gint format;
-      gulong nitems;
-      gulong bytes_after;
-      guchar *data;
-      gulong *current_desktop;
-      GdkDisplay *display = gdk_drawable_get_display (window);
-      
       /* Request unstick from viewport */
       gdk_wmspec_change_state (FALSE, window,
                               gdk_atom_intern_static_string ("_NET_WM_STATE_STICKY"),
                               NULL);
 
-      /* Get current desktop, then set it; this is a race, but not
-       * one that matters much in practice.
-       */
-      XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window),
-                         gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"),
-                          0, G_MAXLONG,
-                          False, XA_CARDINAL, &type, &format, &nitems,
-                          &bytes_after, &data);
-
-      if (type == XA_CARDINAL)
-        {
-         current_desktop = (gulong *)data;
-         
-          xev.xclient.type = ClientMessage;
-          xev.xclient.serial = 0;
-          xev.xclient.send_event = True;
-          xev.xclient.window = GDK_WINDOW_XWINDOW (window);
-         xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
-          xev.xclient.format = 32;
-
-          xev.xclient.data.l[0] = *current_desktop;
-          xev.xclient.data.l[1] = 0;
-          xev.xclient.data.l[2] = 0;
-          xev.xclient.data.l[3] = 0;
-          xev.xclient.data.l[4] = 0;
-      
-          XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
-                      SubstructureRedirectMask | SubstructureNotifyMask,
-                      &xev);
-
-          XFree (current_desktop);
-        }
+      move_to_current_desktop (window);
     }
   else
     {
index 24eae26ba5c24f404b20dffabfc1bdcf663f81f4..eec02636aff6aa07cc0334b637e411dfaa4bb56f 100644 (file)
@@ -1224,6 +1224,17 @@ grab_color_at_mouse (GdkScreen *screen,
   priv = colorsel->private_data;
   
   image = gdk_drawable_get_image (root_window, x_root, y_root, 1, 1);
+  if (!image)
+    {
+      gint x, y;
+      GdkDisplay *display = gdk_screen_get_display (screen);
+      GdkWindow *window = gdk_display_get_window_at_pointer (display, &x, &y);
+      if (!window)
+       return;
+      image = gdk_drawable_get_image (window, x, y, 1, 1);
+      if (!image)
+       return;
+    }
   pixel = gdk_image_get_pixel (image, 0, 0);
   g_object_unref (image);
 
@@ -1429,11 +1440,11 @@ get_screen_color (GtkWidget *button)
       gtk_widget_add_events (priv->dropper_grab_widget,
                              GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
       
+      gtk_widget_set_parent_window (priv->dropper_grab_widget, 
+                                   GTK_WIDGET (colorsel)->window);
       gtk_widget_show (priv->dropper_grab_widget);
 
       gdk_window_set_user_data (priv->dropper_grab_widget->window, colorsel);
-      gdk_window_reparent (priv->dropper_grab_widget->window, 
-                          GTK_WIDGET (colorsel)->window, 0, 0);
     }
 
   if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
index 3cf3a2ae9f00f31a4f14c4b905c6d5093b558136..c944b770be78f317d841f3958b00a0cf16a2d9b0 100644 (file)
@@ -214,11 +214,16 @@ gtk_invisible_get_screen (GtkInvisible *invisible)
 static void
 gtk_invisible_realize (GtkWidget *widget)
 {
+  GdkWindow *parent;
   GdkWindowAttr attributes;
   gint attributes_mask;
 
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
+  parent = gtk_widget_get_parent_window (widget);
+  if (parent == NULL)
+    parent = gtk_widget_get_root_window (widget);
+
   attributes.x = -100;
   attributes.y = -100;
   attributes.width = 10;
@@ -230,8 +235,7 @@ gtk_invisible_realize (GtkWidget *widget)
 
   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
 
-  widget->window = gdk_window_new (gtk_widget_get_root_window (widget),
-                                  &attributes, attributes_mask);
+  widget->window = gdk_window_new (parent, &attributes, attributes_mask);
                                              
   gdk_window_set_user_data (widget->window, widget);
   
index c43b35cd729f178bb34183f14a0f8f87550e690c..d9d3b53bd29482fd7b04d219969baac086e018bb 100644 (file)
@@ -5822,11 +5822,11 @@ gtk_widget_get_parent_window   (GtkWidget           *widget)
   GdkWindow *parent_window;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
-  g_return_val_if_fail (widget->parent != NULL, NULL);
   
   parent_window = g_object_get_qdata (G_OBJECT (widget), quark_parent_window);
 
-  return (parent_window != NULL) ? parent_window : widget->parent->window;
+  return (parent_window != NULL) ? parent_window : 
+        (widget->parent != NULL) ? widget->parent->window : NULL;
 }
 
 /**